/*
Copyright (C) 2006,2007 StrmnNrmn

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "stdafx.h"

#include <stdlib.h>
#include <stdio.h>

#include "System.h"
#include "Debug/DBGConsole.h"
#include "Debug/DebugLog.h"
#include "Interface/RomDB.h"
#include "Core/RomSettings.h"
#include "Core/Memory.h"
#include "Core/CPU.h"
#include "Core/Cheats.h"
#include "Core/PIF.h"
#include "Core/CPU.h"
#include "Core/Save.h"
#include "Input/InputManager.h"
#include "Utility/Profiler.h"
#include "Utility/IO.h"
#include "Utility/Preferences.h"
#include "Utility/Timer.h"
#include "Utility/Thread.h"
#include "Utility/ModulePSP.h"

#include "Graphics/GraphicsContext.h"

#include "SysARM/UI/UIContext.h"
#include "SysARM/UI/MainMenuScreen.h"
#include "SysARM/UI/PauseScreen.h"
#include "SysARM/UI/SplashScreen.h"
#include "SysARM/Graphics/DrawText.h"
#include "SysARM/Utility/PathsPSP.h"
#include "SysARM/Utility/Buttons.h"

#include "HLEGraphics/TextureCache.h"

#include "Test/BatchTest.h"

#include "ConfigOptions.h"


char gDaedalusExePath[MAX_PATH+1] = DAEDALUS_PSP_PATH( "" );


extern bool InitialiseJobManager();
//*************************************************************************************
static void Finalise()
{
	System_Finalize();
}

#ifdef DAEDALUS_PROFILE_EXECUTION
//*************************************************************************************
//
//*************************************************************************************
static void	DumpDynarecStats( float elapsed_time )
{
	// Temp dynarec stats
	extern u64 gTotalInstructionsEmulated;
	extern u64 gTotalInstructionsExecuted;
	extern u32 gTotalRegistersCached;
	extern u32 gTotalRegistersUncached;
	extern u32 gFragmentLookupSuccess;
	extern u32 gFragmentLookupFailure;

	u32		dynarec_ratio( 0 );

	if(gTotalInstructionsExecuted + gTotalInstructionsEmulated > 0)
	{
		float fRatio = float(gTotalInstructionsExecuted * 100.0f / float(gTotalInstructionsEmulated+gTotalInstructionsExecuted));

		dynarec_ratio = u32( fRatio );

		//gTotalInstructionsExecuted = 0;
		//gTotalInstructionsEmulated = 0;
	}

	u32		cached_regs_ratio( 0 );
	if(gTotalRegistersCached + gTotalRegistersUncached > 0)
	{
		float fRatio = float(gTotalRegistersCached * 100.0f / float(gTotalRegistersCached+gTotalRegistersUncached));

		cached_regs_ratio = u32( fRatio );
	}

	const char * const TERMINAL_SAVE_CURSOR			= "\033[s";
	const char * const TERMINAL_RESTORE_CURSOR		= "\033[u";
//	const char * const TERMINAL_TOP_LEFT			= "\033[2A\033[2K";
	const char * const TERMINAL_TOP_LEFT			= "\033[H\033[2K";

	printf( TERMINAL_SAVE_CURSOR );
	printf( TERMINAL_TOP_LEFT );

	printf( "Frame: %dms, DynaRec %d%%, Regs cached %d%%, Lookup success %d/%d", u32(elapsed_time * 1000.0f), dynarec_ratio, cached_regs_ratio, gFragmentLookupSuccess, gFragmentLookupFailure );

	printf( TERMINAL_RESTORE_CURSOR );
	fflush( stdout );

	gFragmentLookupSuccess = 0;
	gFragmentLookupFailure = 0;
}
#endif

#ifdef DAEDALUS_DEBUG_DISPLAYLIST
extern bool gDebugDisplayList;
#include "HLEGraphics/DLParser.h"
#endif
//*************************************************************************************
//
//*************************************************************************************
#ifdef DAEDALUS_PROFILE_EXECUTION	
static CTimer		gTimer;
#endif

void HandleEndOfFrame()
{
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
	if(gDebugDisplayList)
		return;
#endif

	DPF( DEBUG_FRAME, "********************************************" );

	bool		activate_pause_menu( false );
	//
	//	Figure out how long the last frame took
	//
#ifdef DAEDALUS_PROFILE_EXECUTION	
	DumpDynarecStats( elapsed_time );
#endif
	//
	//	Enter the debug menu as soon as select is newly pressed
	//
#ifdef OLD

	//
	if(oldButtons != pad.Buttons)
	{
		if( gCheatsEnabled && (pad.Buttons & PSP_CTRL_SELECT) )
		{
			CheatCodes_Activate( GS_BUTTON );
		}

		if(pad.Buttons & PSP_CTRL_HOME)
		{
			while(!activate_pause_menu)
			{
				sceCtrlPeekBufferPositive(&pad, 1);
				if(!(pad.Buttons & PSP_CTRL_HOME))
				{
					activate_pause_menu = true;
				}
			}
		}
	}
	oldButtons = pad.Buttons;

	if(activate_pause_menu)
	{
		// See how much texture memory we're using
		//CTextureCache::Get()->DropTextures();
//#ifdef DAEDALUS_DEBUG_MEMORY
		//CVideoMemoryManager::Get()->DisplayDebugInfo();
//#endif

		// No longer needed since we save normally now, and not jsut when entering the pause menu ;)
		//Save::Flush(true);

		// switch back to the LCD display
		CGraphicsContext::Get()->SwitchToLcdDisplay();

		// Call this initially, to tidy up any state set by the emulator
		CGraphicsContext::Get()->ClearAllSurfaces();

		CDrawText::Initialise();

		CUIContext *	p_context( CUIContext::Create() );

		if(p_context != NULL)
		{
			// Already set in ClearBackground() @ UIContext.h 
			//p_context->SetBackgroundColour( c32( 94, 188, 94 ) );		// Nice green :)

			CPauseScreen *	pause( CPauseScreen::Create( p_context ) );
			pause->Run();
			delete pause;
			delete p_context;
		}

		CDrawText::Destroy();

		//
		// Commit the preferences database before starting to run
		//
		CPreferences::Get()->Commit();
	}
	//
	//	Reset the elapsed time to avoid glitches when we restart
	//
#ifdef DAEDALUS_PROFILE_EXECUTION	
	gTimer.Reset();
#endif

}
#endif
//*************************************************************************************
// Here's where we load up the GUI
//*************************************************************************************
static void DisplayRomsAndChoose(bool show_splash)
{
	// switch back to the LCD display
	CGraphicsContext::Get()->SwitchToLcdDisplay();

	CDrawText::Initialise();

	CUIContext *	p_context( CUIContext::Create() );

	if(p_context != NULL)
	{
		// Already set in ClearBackground() @ UIContext.h 
		//const c32		BACKGROUND_COLOUR = c32( 107, 188, 255 );		// blue
		//const c32		BACKGROUND_COLOUR = c32( 92, 162, 219 );		// blue
		//const c32		BACKGROUND_COLOUR = c32( 1, 1, 127 );			// dark blue
		//const c32		BACKGROUND_COLOUR = c32( 1, 127, 1 );			// dark green

		//p_context->SetBackgroundColour( BACKGROUND_COLOUR );

		if( show_splash )
		{
			CSplashScreen *		p_splash( CSplashScreen::Create( p_context ) );
			p_splash->Run();
			delete p_splash;
		}

		CMainMenuScreen *	p_main_menu( CMainMenuScreen::Create( p_context ) );
		p_main_menu->Run();
		delete p_main_menu;
	}

	delete p_context;

	CDrawText::Destroy();
}

//*************************************************************************************
// This is our main loop
//*************************************************************************************
extern "C"
{
int main(int argc, char* argv[])
{
	if( Initialize() )
	{
#ifdef DAEDALUS_BATCH_TEST_ENABLED
		if( argc > 1 )
		{
			BatchTestMain( argc, argv );
		}
#else
		//Makes it possible to load a ROM directly without using the GUI
		//There are no checks for wrong file name so be careful!!!
		//Ex. from PSPLink -> ./Daedalus.prx "Roms/StarFox 64.v64" //Corn
		if( argc > 1 )
		{
			printf("Loading %s\n", (char*)argv[1] );
			System_Open( (char*)argv[1] );
			CPU_Run();
			System_Close();
			Finalise();
			quit(1);
			return 0;
		}
#endif

		bool show_splash = true;
		for(;;)
		{
			DisplayRomsAndChoose( show_splash );
			show_splash = false;

			//
			// Commit the preferences and roms databases before starting to run
			//
			CRomDB::Get()->Commit();
			CPreferences::Get()->Commit();

			CPU_Run();
			System_Close();
		}

		Finalise();
	}

	quit(1);
	return 0;
}
}
